<?php
//рус
include_once (_CORE_PATH . "lib_prototype.php");
class session_class implements lib_prototype_class
{
    private static $isStart = false;
    private $_lockId = false;
    private $_maxLifeTime;
    private $_ip;
    private $_httpUserAgent;
    private $_serializedData = '';
    private $_isDataRead = false;
    private $_generateNew = false;
    private $_isUpdate = true;
    private $_sessionExists = false;
    private $_isCheckIp = false;
    private $_isCheckUserAgent = true;

    private $_source;
    
    protected $_libs;

    function __construct ()
    {
        $this->_libs = SysLoader::GetLibCollection();

        $this->_source = MozgSource::get('default');
        
        $this->_isCheckIp = false;
        $this->_isCheckUserAgent = true;
        $gc_maxLifeTime = 1800;
        $gc_probability = 1;
        $gc_divisor = 1000;
        // if $gc_maxLifeTime is specified and is an integer number
        if ($gc_maxLifeTime != "" && is_integer($gc_maxLifeTime)) {
            // set the new value
            @ini_set('session.gc_maxlifetime', $gc_maxLifeTime);
        }
        // if $gc_probability is specified and is an integer number
        if ($gc_probability != "" && is_integer($gc_probability)) {
            // set the new value
            @ini_set('session.gc_probability', $gc_probability);
        }
        // if $gc_divisor is specified and is an integer number
        if ($gc_divisor != "" && is_integer($gc_divisor)) {
            // set the new value
            @ini_set('session.gc_divisor', $gc_divisor);
        }
        @ini_set('session.use_only_cookies', "1");
        @ini_set('session.save_handler', 'user');
        session_set_cookie_params(315360000, "/"); //10 лет
        $this->_maxLifeTime = $gc_maxLifeTime;
        $this->_ip = $this->getIPAddr();
        $this->_httpUserAgent = md5($_SERVER["HTTP_USER_AGENT"]);
        $this->_serializedData = '';
        $this->_isDataRead = false;
        $this->_generateNew = false;
        $this->_isUpdate = true;
        $this->_sessionExists = false;
    }
    function start($generate_new_id = false)
    {
    	$this->_generateNew = (bool)$generate_new_id || (bool)$this->_generateNew;
        if (self::$isStart) 
        {
        	if ($this->_generateNew) $this->regenerate_id();
        	return;
        }

        self::$isStart = true;
        session_name(MozgCfg::GetProp('global//sessionName'));
        // register the new handler
        session_set_save_handler(array($this , 'open'), array($this , 'close'), array($this , 'read'), array($this , 'write'), array($this , 'destroy'), array($this , 'gc'));
        //$this->f = fopen('session.txt', 'w+');
        session_start();
        //$this->_generateNew = true;
        if ($this->_generateNew) 
        {
            $this->regenerate_id();
        }
        if ($_SESSION['session_expire'] && ($_SESSION['session_expire'] - $this->_maxLifeTime <= time())) {
            unset($_SESSION['session_expire']);
        }
    }
    function IsCookie ()
    {
        return isset($_COOKIE[MozgCfg::GetProp('global//sessionName')]);
    }
    function IsSession ()
    {
        $this->read($_COOKIE[MozgCfg::GetProp('global//sessionName')]);
        return $this->_sessionExists;
    }
    /**
     *  Deletes all data related to the session
     *
     *  @return void
     */
    function stop ()
    {
        if (! self::$isStart) return;
        setcookie(session_name(), $this->get_session_id(), time() - 1000, '/');
        session_unset();
        session_destroy();
    }
    /**
     *  Regenerates the session id.
     *
     *  <b>Call this method whenever you do a privilege change!</b>
     *
     *  @return void
     */
    private function regenerate_id()
    { //fwrite($this->f, "regenerate\n");
        $this->_generateNew = false;
        if (! self::$isStart || ! $this->IsCookie()) return;
        session_regenerate_id(true);
    }
    function get_session_id ()
    {
        return session_id();
    }
    /**
     *  Custom open() function
     *
     *  @access private
     */
    function open ($save_path, $session_name)
    { //fwrite($this->f, "open\n");
        if (! self::$isStart) return true;
        return true;
    }
    /**
     *  Custom close() function
     *
     *  @access private
     */
    function close ()
    {
        if (! self::$isStart) return true;
        $this->unlock();
        return true;
    }
    function lock ($lockId)
    {
        if (! $lockId) {
            $this->_lockId = false;
            return;
        }
        $lockId = (string) $lockId;
        $this->_source->query("SELECT GET_LOCK(" . $this->_source->quote('sess_' .$lockId) . ", 60)");
        //sleep(50);
        $this->_lockId = $lockId;
    }
    function unlock ()
    {
        if (! $this->_lockId) return;
        $this->_source->query("SELECT RELEASE_LOCK(" . $this->_source->quote('sess_' .$this->_lockId) . ")");
    }
    /**
     *  Custom read() function
     *
     *  @access private
     */
    function read ($session_id)
    { //fwrite($this->f, "read\n");
        //if (!$this->is_start) return;
        if ($this->_isDataRead) return $this->_serializedData;
        $this->_isDataRead = true;
        // блокируем сессию для параллельного процесса
        $this->lock($session_id);
        if (! $this->IsCookie()) {
            $this->_serializedData = '';
            return $this->_serializedData;
        }
        $session_id = (string) $session_id;

        $stmt = $this->_source->query("SELECT
								                session_data,
								                http_user_agent,
								                INET_NTOA(user_ip) user_ip,
								                session_expire
								            FROM
								                %%session_data%%
								            WHERE
								                session_id = " . $this->_source->quote($session_id));

        $fields = $stmt->fetch();

        if (! $fields || ($this->_isCheckUserAgent && ($fields['http_user_agent'] != $this->_httpUserAgent)) || ($this->_isCheckIp && ($fields['user_ip'] != $this->_ip)) || ($fields['session_expire'] <= (time() - $this->_maxLifeTime))) {
            $this->_generateNew = true;
            $this->_serializedData = '';
            return $this->_serializedData;
        }
        $this->_sessionExists = true;
        $this->_serializedData = (string) $fields["session_data"];
        return $this->_serializedData;
    }
    /**
     *  Custom write() function
     *
     *  @access private
     */
    function write ($session_id, $session_data)
    {
        if (! self::$isStart)
            return true;
        if (! $this->_isUpdate)
            return true;
            //fwrite($this->f, "write\n");
        $is_success = false;
        if ($_SESSION['session_expire'] && ($_SESSION['session_expire'] - $this->_maxLifeTime > time())) {
            $expire = $_SESSION['session_expire'] - $this->_maxLifeTime;
        } else {
            $expire = time();//'UNIX_TIMESTAMP()';
        }
        $stmt = $this->_source->query("SELECT
		        								http_user_agent,
		        								INET_NTOA(user_ip) as user_ip
								            FROM
								                %%session_data%%
								            WHERE
								                session_id = " . $this->_source->quote($session_id));

        $r = $stmt->fetch();

        if ($r) {
            if ((! $this->_isCheckUserAgent || ($r['http_user_agent'] == $this->_httpUserAgent)) && (! $this->_isCheckIp || ($r['user_ip'] == $this->_ip))) {
                $this->_source->exec("
		                UPDATE
		                    %%session_data%%
		                SET
		                    session_data = " . $this->_source->quote($session_data) . ",
		                    session_expire = " . $expire . ",
		                    user_id = " . ($_SESSION['user']['is_logged'] ? intval($_SESSION['user']['user_id']) : 'NULL') . ",
		                    user_ip = INET_ATON('" . $this->_ip . "'),
		                    http_user_agent = '" . $this->_httpUserAgent . "'
		                WHERE
			                session_id = " . $this->_source->quote($session_id) . "
		            ");
            }
        } else {
            $this->_source->exec("
                INSERT INTO
                    %%session_data%%
                        (
                            session_id,
                            http_user_agent,
                            user_ip,
                            session_expire,
                            session_data,
                            user_id
                        )
                    VALUES
                        (
                            " . $this->_source->quote($session_id) . ",
                            '" . $this->_httpUserAgent . "',
                            INET_ATON('" . $this->_ip . "'),
                            " . $expire . ",
                            " . $this->_source->quote($session_data) . ",
                            " . ($_SESSION['user']['is_logged'] ? intval($_SESSION['user']['user_id']) : 'NULL') . "
                        )
            ");
        }
    }
    /**
     *  Custom destroy() function
     *
     *  @access private
     */
    function destroy ($session_id)
    { //fwrite($this->f, "destroy\n");
        if (! self::$isStart)
            return true;
        $this->_source->exec("
            DELETE FROM
                %%session_data%%
            WHERE
                session_id = " . $this->_source->quote($session_id) . "
                " . ($this->_isCheckUserAgent ? " AND http_user_agent = '" . $this->_httpUserAgent . "'" : "") . "
                " . ($this->_isCheckIp ? " AND INET_NTOA(user_ip) = '" . $this->_ip . "'" : ""));

        return true;
    }
    /**
     *  Custom gc() function (garbage collector)
     *
     *  @access private
     */
    function gc ($maxLifeTime)
    { //fwrite($this->f, "gc\n");
        //if (!self::$isStart) return;
        $this->_source->exec("
            DELETE FROM
                %%session_data%%
            WHERE
                session_expire < " .(time() - $maxLifeTime) . "
        ");
    }
    function getIPAddr ()
    {
        if (isset($_SERVER['REMOTE_ADDR'])) {
            $_ip = $_SERVER['REMOTE_ADDR'];
        } elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {
            $_ip = $_SERVER['HTTP_CLIENT_IP'];
        } elseif (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
            $_ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
        } else {
            $_ip = 0;
        }
        $ip_arr = explode('.', $_ip);
        return intval($ip_arr[0]) . '.' . intval($ip_arr[1]) . '.' . intval($ip_arr[2]) . '.' . intval($ip_arr[3]);
    }
    function GetValue ($key)
    {
    	$this->start();
    	
        if (isset($_SESSION[$key]))  return $_SESSION[$key];
        return null;
    }
    function SetValue ($key, $val = null)
    {
    	$this->start();
    	
    	if (is_null($val)) 
    	{
    		if (isset($_SESSION[$key])) unset($_SESSION[$key]);
    	}
    	else
    	{
    		$_SESSION[$key] = $val;
    	}
    }
    function AddValue ($key, $val = null)
    {
    	$this->start();
    	
        if (is_array($_SESSION[$key])) $_SESSION[$key][] = $val;
        else $this->SetValue($key, $val);
    }
    function __destruct ()
    {
        if (self::$isStart) return;
        $this->unlock();
    }

    /**
    	время на серваке может не совпадать с временем в MySQL!!!
    */
    function SetExpireDate ($seconds = 0)
    {
    	$this->start();
    	
        if ($seconds <= $this->_maxLifeTime) return;
        $_SESSION['session_expire'] = time() + $seconds;
    }
    function DoNotUpdate ()
    {
        $this->_isUpdate = false;
    }
}
